#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <syscall.h>

#define MAX_THREAD 15000

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int start = 0;

static void usage()
{
    printf("Usage: [-h] [-c thread num ] [ -t execute interval ] [ -n execute times ] \n");
    printf("options:\n");
    printf("-h: help message\n");
    printf("-c: thread number, default 15000\n");
    printf("-t: execute interval (seconds), default 10s \n");
    printf("-n: execute times, default once, 0 means infinite \n");
}

static pid_t gettid(void)
{
    return syscall(__NR_gettid);
}
void *work_fn(void *arg)
{
    int i;
    unsigned long ret = 0;

    pthread_mutex_lock(&mutex);

    //printf("thread %lu is waiting\n", gettid());
    while (!start) {
        pthread_cond_wait(&cond, &mutex);
    }
    pthread_mutex_unlock(&mutex);

    //printf("thread %lu is running\n", gettid());
    for (i = 0; i < 10000; i++) {
        ret += i + (i + 1);
    }
    return NULL;
}

int main(int argc, char *argv[]) {

    int i;
    void *retval;
    long threads = MAX_THREAD;
    long interval = 10;
    int times = 1;
    int infinite = 0;
    char c;
    unsigned long count = 1;

    while ((c = getopt(argc, argv, "hc:t:n:")) != -1) {
        switch (c) {
        case 'c':
            threads = atol(optarg);
            break;
        case 't':
            interval = atol(optarg);
            break;
        case 'n':
            times = atol(optarg);
            break;
        case 'h':
            usage();
            exit(0);
        default:
            printf("invalid option %c\n", c);
            usage();
            exit(1);
        }
    }

    infinite = (times == 0);

    printf("cpu burst simulator: execute %d times, interval: %d, threads: %ld\n",
            times, interval, threads);
    while (infinite || times--) {
        printf("run %lu time\n", count++);
        pthread_t *pids = (pthread_t *)malloc(sizeof(pthread_t) * threads);
        if (pids == NULL) {

            fprintf(stderr, "can not alloc pids array!\n");
            exit(1);
        }

        for (i = 0; i < threads; i++) {
            pthread_create(&pids[i], NULL, work_fn, NULL);
        }

        usleep(1000);
        // start run
        pthread_mutex_lock(&mutex);
        start = 1;
        pthread_cond_broadcast(&cond);
        pthread_mutex_unlock(&mutex);

        for (i = 0; i < threads; i++) {
            pthread_join(pids[i], &retval);
        }

        free(pids);

        // reset
        start = 0;

        // sleep for interval
        if (times) {
            sleep(interval);
        }
    }

    printf("simulate finished.\n");
    return 0;
}
